package com.xneure.utils.bean;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class JdbcHandler extends JdbcTemplate {

	private TransactionStatus transcationStatus;
	private PlatformTransactionManager platformTransactionManager;
	private DefaultTransactionDefinition transactionDefinition;

	@Autowired
	public JdbcHandler(DataSource ds) {
		super(ds);
	}

	@Override
	public int getFetchSize() {
		return 1000;
	}

	@Override
	public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
		try {
			boolean isQuery = action.getClass().getName().toLowerCase().indexOf("query") > 0;
			T execute;
			if (isQuery == false && isAutoTran()) {
				beginTranstaion();
				execute = super.execute(action);
				commit();
			} else {
				execute = super.execute(action);
				if (isAutoTran()) {
					commit();
				}
			}
			return execute;
		} catch (Exception e) {
			rollback();
			throw new TransientDataAccessResourceException(e.getMessage());
		}
	}

	@Override
	public <T> T execute(StatementCallback<T> action) throws DataAccessException {
		try {
			boolean isQuery = action.getClass().getName().toLowerCase().indexOf("query") > 0;
			T execute;
			if (isQuery == false && isAutoTran()) {
				beginTranstaion();
				execute = super.execute(action);
				commit();
			} else {
				execute = super.execute(action);
				if (isAutoTran()) {
					commit();
				}
			}
			return execute;
		} catch (Exception e) {
			rollback();
			throw new TransientDataAccessResourceException(e.getMessage());
		}
	}

	@Override
	public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
		try {
			boolean isQuery = action.getClass().getName().toLowerCase().indexOf("query") > 0;
			T execute;
			if (isQuery == false && isAutoTran()) {
				beginTranstaion();
				execute = super.execute(psc, action);
				commit();
			} else {
				execute = super.execute(psc, action);
				if (isAutoTran()) {
					commit();
				}
			}
			return execute;
		} catch (Exception e) {
			rollback();
			throw new TransientDataAccessResourceException(e.getMessage());
		}
	}

	@Override
	public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action) throws DataAccessException {
		try {
			boolean isQuery = action.getClass().getName().toLowerCase().indexOf("query") > 0;
			T execute;
			if (isQuery == false && isAutoTran()) {
				beginTranstaion();
				execute = super.execute(csc, action);
				commit();
			} else {
				execute = super.execute(csc, action);
				if (isAutoTran()) {
					commit();
				}

			}
			return execute;
		} catch (Exception e) {
			rollback();
			throw new TransientDataAccessResourceException(e.getMessage());
		}
	}

	private boolean isAutoTran() {
		return null == transcationStatus;
	}

	@Override
	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		transactionDefinition = new DefaultTransactionDefinition();
		transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
		transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		platformTransactionManager = new DataSourceTransactionManager(getDataSource());

	}

	public PlatformTransactionManager getPlatformTransactionManager() {
		return platformTransactionManager;
	}

	public DefaultTransactionDefinition getTransactionDefinition() {
		return transactionDefinition;
	}

	public TransactionStatus getTranscationStatus() {
		return transcationStatus;
	}

	public void rollback() {
		if (transcationStatus != null) {
			platformTransactionManager.rollback(transcationStatus);
			transcationStatus = null;
		}
	}

	public void commit() {
		if (transcationStatus != null) {
			platformTransactionManager.commit(transcationStatus);
			transcationStatus = null;
		}
	}

	public void beginTranstaion() {
		transcationStatus = platformTransactionManager.getTransaction(transactionDefinition);

	}

	public void recycleSpace() {
		recycleCmd("full");
	}

	public void recycleSpace(String tableName) {
		recycleCmd(tableName);
	}

	private void recycleCmd(String cmd) {
		// try {
		// BasicDataSource ds = (BasicDataSource) getDataSource();
		// Class.forName(ds.getDriverClassName()).newInstance();
		// Connection con = DriverManager.getConnection(ds.getUrl(),
		// ds.getUsername(), ds.getPassword());
		// con.createStatement().execute("vacuum ".concat(cmd));
		// con.close();
		// } catch (Exception e) {
		// }
	}
}
